package cn.jbolt.api.common.controller;

import cn.hutool.core.util.RandomUtil;
import cn.jbolt.admin.appdevcenter.ApplicationService;
import cn.jbolt.admin.wechat.mpinfo.WechatMpinfoService;
import cn.jbolt.admin.wechat.mpinfo.WechatMpinfoType;
import cn.jbolt.admin.wechat.user.WechatUserService;
import cn.jbolt.base.JBoltWechatApi;
import cn.jbolt.base.JBoltWechatApi.Type;
import cn.jbolt.common.model.WechatUser;
import cn.jbolt.common.util.CACHE;
import cn.jbolt.core.api.JBoltApiBaseService;
import cn.jbolt.core.api.JBoltApiKit;
import cn.jbolt.core.api.JBoltApiRet;
import cn.jbolt.core.api.JBoltApiUserBean;
import cn.jbolt.core.model.Application;
import cn.jbolt.core.para.JBoltPara;
import cn.jbolt.core.service.JBoltFileService;
import cn.jbolt.core.util.JBoltCamelCaseUtil;
import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.wxaapp.api.WxaUserApi;

import java.util.Date;
import java.util.Map;

/**
 * 微信小程序XfUserApiService 业务处理
 *
 * @ClassName: XfUserApiService
 * @author: xiaofu QQ：593391262
 * @date: 2022年7月25日
 */
public class XfUserApiService extends JBoltApiBaseService {
    @Inject
    private WechatUserService wechatUserService;
    @Inject
    private WechatMpinfoService wechatMpinfoService;
    @Inject
    private ApplicationService applicationService;
    @Inject
    private JBoltFileService jBoltFileService;

    /**
     * 微信小程序用户进入小程序 调用登录
     *
     * @param code
     * @return
     */
    @Before(Tx.class)
    public JBoltApiRet login(String code) {
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        if (notOk(code)) {
            return JBoltApiRet.WX_LOGIN_CODE_NULL(application);
        }
        //得到微信小程序配置的APPID
        String wechatAppId = JBoltApiKit.getWechatAppId();
        Long mpId = JBoltApiKit.getWechatMpId();
        //执行API调用获取sessionKey和OpenId unionid
        ApiResult apiResult = JBoltWechatApi.use(wechatAppId, Type.MP_WXA).call(() -> WxaUserApi.getSessionKey(code));
        //调用成功
        if (apiResult.isSucceed()) {
            String openId = apiResult.getStr("openid");
            String unionId = apiResult.getStr("unionid");
            String sessionKey = apiResult.getStr("session_key");
            //从cache里拿到对应微信用户
            WechatUser wechatUser = CACHE.me.getApiWechatUserByMpOpenId(mpId, openId);
            if (wechatUser != null) {
                Ret ret = wechatUserService.updateWxaUserLoginInfo(application.getLinkTargetId(), wechatUser, openId, unionId, sessionKey);
                if (ret.isFail()) {
                    return JBoltApiRet.API_FAIL(application, "登录失败," + ret.getStr("msg"));
                }
                JBoltApiKit.setApplyJwtUser(JBoltApiKit.processBindUser(new JBoltApiUserBean(application.getId(), wechatUser.getId(), wechatUser.getNickname(), sessionKey), wechatUser.getBindUser()));
                return JBoltApiRet.successWithData(Kv.by("status", 1).set("sessionKey", sessionKey).set("openid", openId).set("unionId", unionId));
            } else {
                //两种方案
                /*
                1.如果没有，说明是第一次登录 保存用户信息。因没有用户资料 昵称等手机信息，已不推荐
                wechatUser = wechatUserService.saveWxaUser(application.getLinkTargetId(), openId, unionId, sessionKey);
                if(wechatUser==null){
                	return JBoltApiRet.WECHAT_XCX_USER_CREATE_FAIL(application);
                }
                JBoltApiKit.setApplyJwtUser(JBoltApiKit.processBindUser(new JBoltApiUserBean(application.getId(), 0, null,null, sessionKey), null));*/
                //2 返回客户端提示新用户需要注册
                return JBoltApiRet.fail(4080, "新用户需注册", Kv.by("status", -1).set("sessionKey", sessionKey).set("openid", openId).set("unionId", unionId));
            }

        }
        return JBoltApiRet.API_FAIL(application, "登录失败," + apiResult.getErrorMsg());
    }

    /**
     * 微信小程序注册 通过手机号
     *
     * @param param
     * @return
     */
    @Before(Tx.class)
    public JBoltApiRet registerByPhone(JBoltPara param) {
        String errMsg = param.getString("errMsg");
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        if (StrKit.isBlank(errMsg) || errMsg.equalsIgnoreCase("getphonenumber:ok") == false) {
            return JBoltApiRet.WECHAT_XCX_GETPHONENUMBER_FAIL(application);
        }
        //得到微信小程序配置的APPID
        String wechatAppId = JBoltApiKit.getWechatAppId();
        Long mpId = JBoltApiKit.getWechatMpId();
        String sessionKey = param.getString("sessionKey");
        String openId = param.getString("openid");
        String unionId = param.getString("unionid");
        //准备解密
        String encryptedData = param.getString("encryptedData");
        String iv = param.getString("iv");
        ApiResult userInfoResult;
        try {
            userInfoResult = JBoltWechatApi.use(wechatAppId, Type.MP_WXA).call(() -> WxaUserApi.getUserInfo(sessionKey, encryptedData, iv));
            if (!userInfoResult.isSucceed()) {
                return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
            }
        } catch (Exception e) {
            return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
        }
        String phone = userInfoResult.getStr("purePhoneNumber");
        if (notOk(phone)) {
            return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
        }
        WechatUser phoneToUser = findByPhoneToUser(mpId, phone);
        if (phoneToUser != null) {
            //当前手机用户存在
            if (isOk(phoneToUser.getOpenId())) {
                //TODO 是否覆盖上次的登录小程序XcxOpenId
                return JBoltApiRet.fail(4050, "用户手机号【" + phone + "】已经绑定其他微信，请输入其它手机号", Kv.by("status", -1).set("sessionKey", sessionKey));
            } else {
                //可以更新用户信息 绑定
                Ret ret = wechatUserService.updateWxaUserLoginInfo(application.getLinkTargetId(), phoneToUser, openId, unionId, sessionKey);
                if (ret.isFail()) {
                    return JBoltApiRet.API_FAIL(application, "更新失败," + ret.getStr("msg"));
                }
                JBoltApiKit.setApplyJwtUser(JBoltApiKit.processBindUser(new JBoltApiUserBean(application.getId(), phoneToUser.getId(), phoneToUser.getNickname(), sessionKey), phoneToUser.getBindUser()));
                return JBoltApiRet.success();
            }
        }
        //新用户 更新到数据库里
        Ret ret = saveWxaXcxUserAndPhone(mpId, wechatAppId, openId, unionId, sessionKey, param, userInfoResult);
        if (ret.isFail()) {
            return JBoltApiRet.WECHAT_XCX_UPDATE_USER_PHONENUMBER_FAIL(application, ret.getStr("msg"));
        }
        WechatUser wechatUser = (WechatUser) ret.get("data");
        JBoltApiKit.setApplyJwtUser(JBoltApiKit.processBindUser(new JBoltApiUserBean(application.getId(), wechatUser.getId(), wechatUser.getNickname(), sessionKey), wechatUser.getBindUser()));
        return JBoltApiRet.success();
    }


    public WechatUser findByPhoneToUser(Object _id, String phone) {
        Record record = Db.findFirst("select * from jb_wechat_user_" + _id + " where phone=?", phone);
        if (record == null) {
            return null;
        }
        return new WechatUser()._setAttrs(record.getColumns());
    }

    /**
     * 微信小程序用户注册
     *
     * @param mpId
     * @param wechatAppId
     * @param xcxOpenId
     * @param unionId
     * @param sessionKey
     * @param userInfo
     * @param phoneInfo
     * @return
     */
    public Ret saveWxaXcxUserAndPhone(Long mpId, String wechatAppId, String xcxOpenId, String unionId, String sessionKey, JBoltPara userInfo, ApiResult phoneInfo) {
        Map<String, String> warterMark = phoneInfo.get("watermark");
        //判断水印
        if (warterMark == null) {
            return Ret.fail(String.format("微信小程序用户手机号信息更新时,未获取到appId[%s-%s]", mpId));
        }
        //判断水印里的APPID
        String waterMarkAppId = warterMark.get("appid");
        if (wechatAppId.equals(waterMarkAppId) == false) {
            return Ret.fail(String.format("微信小程序用户手机号信息更新时,appId不匹配[%s-%s]", mpId));
        }
        Date now = new Date();
        WechatUser wechatUser = new WechatUser();
        wechatUser.setEnable(true);
        wechatUser.setIsChecked(false);
        wechatUser.setOpenId(xcxOpenId);
        wechatUser.setSource(WechatMpinfoType.XCX.getValue());
        wechatUser.setMpId(mpId);
        wechatUser.setUnionId(unionId);
        wechatUser.setSessionKey(sessionKey);
        wechatUser.setSubscibe(true);
        wechatUser.setSubscribeTime(now);
        wechatUser.setFirstLoginTime(now);
        wechatUser.setLastLoginTime(now);
        wechatUser.setCreateTime(now);
        wechatUser.setNickname(userInfo.getString("nickName"));
        wechatUser.setSource(1);
        wechatUser.setSex(userInfo.getInteger("gender"));
        wechatUser.setCountry(userInfo.getString("country"));
        wechatUser.setProvince(userInfo.getString("province"));
        wechatUser.setCity(userInfo.getString("city"));
        wechatUser.setHeadImgUrl(userInfo.getString("avatarUrl"));
        wechatUser.setLanguage(userInfo.getString("language"));
        wechatUser.setPhone(phoneInfo.getStr("purePhoneNumber"));
        wechatUser.setPhoneCountryCode(phoneInfo.getStr("countryCode"));
        wechatUser.setUpdateTime(now);
        Record record = wechatUser.toRecord();
        Ret ret = wechatUserService.save(mpId, record);
        wechatUser.setId(record.getLong("id"));
        return ret.isOk() ? Ret.ok().set("data", wechatUser) : Ret.fail(String.format("注册微信小程序用户手机号注册失败[%s:%s]", mpId));
    }

    /**
     * 微信小程序手机号更新
     *
     * @param param
     * @return
     */
    @Before(Tx.class)
    public JBoltApiRet updateWechatPhone(JBoltPara param) {
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        //得到微信小程序配置的APPID
        String wechatAppId = JBoltApiKit.getWechatAppId();
        Long mpId = JBoltApiKit.getWechatMpId();
        Object userUuid = JBoltApiKit.getApiUserId();
        //用户自身的信息
        WechatUser oldWechatUser = wechatUserService.findByIdToWechatUserFromCache(mpId, userUuid);
        if (oldWechatUser == null) {
            return JBoltApiRet.API_FAIL(application, "无法获取当前用户信息");
        }
        String sessionKey = param.getString("sessionKey");
        //准备解密
        String encryptedData = param.getString("encryptedData");
        String iv = param.getString("iv");
        if (notOk(sessionKey) || notOk(encryptedData) || notOk(iv)) {
            return JBoltApiRet.API_FAIL(application, "无效信息");
        }
        ApiResult userInfoResult;
        try {
            userInfoResult = JBoltWechatApi.use(wechatAppId, Type.MP_WXA).call(() -> WxaUserApi.getUserInfo(sessionKey, encryptedData, iv));
            if (!userInfoResult.isSucceed()) {
                return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
            }
        } catch (Exception e) {
            return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
        }
        String phone = userInfoResult.getStr("purePhoneNumber");
        if (notOk(phone)) {
            return JBoltApiRet.WECHAT_XCX_DECRYPTUSERINFO_FAIL(application);
        }
        //手机号相等 无需更新
        if (!phone.equals(oldWechatUser.getPhone())) {
            WechatUser phoneToUser = findByPhoneToUser(mpId, phone);
            if (phoneToUser != null) {
                //当前手机用户存在
                return JBoltApiRet.API_FAIL(application, "用户手机号【" + phone + "】已经绑定其他账号，请输入其它手机号");
            } else {
                //新的手机用户不存在 可以更新
                Ret ret = wechatUserService.updateWxaPhoneNumberByDecrypt(mpId, wechatAppId, oldWechatUser.getId(), userInfoResult);
                if (ret.isFail()) {
                    return JBoltApiRet.WECHAT_XCX_UPDATE_USER_PHONENUMBER_FAIL(application, ret.getStr("msg"));
                }
            }
        }
        return JBoltApiRet.successWithData(Kv.by("phone", phone));
    }

    /**
     * 获取自身微信用户信息
     *
     * @return
     */
    public JBoltApiRet getMyWechatUserInfo() {
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        Object userId = JBoltApiKit.getApiUserId();
        Long mpId = JBoltApiKit.getWechatMpId();
        WechatUser wechatUser = wechatUserService.findByIdToWechatUserFromCache(mpId, userId);
        if (wechatUser == null) {
            return JBoltApiRet.API_FAIL(application, "无法获取当前用户信息");
        }
        return JBoltApiRet.API_SUCCESS_WITH_DATA(wechatUser);
    }

    public JBoltApiRet updateUserInfo(JBoltPara param) {
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        Object userId = JBoltApiKit.getApiUserId();
        Long mpId = JBoltApiKit.getWechatMpId();
        WechatUser wechatUser = wechatUserService.findByIdToWechatUserFromCache(mpId, userId);
        if (wechatUser == null) {
            return JBoltApiRet.API_FAIL(application, "无法获取当前用户信息");
        }
        String realname = param.getString("realname");
        Integer sex = param.getIntValue("sex");

        String nickname = param.getString("nickname");
        String headImgUrl = param.getString("headImgUrl");

        if (isOk(realname)) {
            wechatUser.setRealname(realname);
        }
        if (sex != null) {
            wechatUser.setSex(sex);
        }
        if (isOk(nickname)) {
            wechatUser.setNickname(nickname);
        }
        if (isOk(headImgUrl)) {
            wechatUser.setHeadImgUrl(headImgUrl);
        }
        Ret ret = wechatUserService.updateWxaUserLoginInfo(mpId, wechatUser, wechatUser.getOpenId(), wechatUser.getUnionId(), wechatUser.getSessionKey());
        if (ret.isFail()) {
            return JBoltApiRet.API_FAIL(application, "更新用户信息失败");
        }
        return JBoltApiRet.API_SUCCESS;
    }

    /**
     * 删除信息
     *
     * @return
     */
    public JBoltApiRet deleteMember() {
        //获取当前访问Application
        Application application = JBoltApiKit.getApplication();
        Object userId = JBoltApiKit.getApiUserId();
        Long mpId = JBoltApiKit.getWechatMpId();
        WechatUser wechatUser = wechatUserService.findByIdToWechatUserFromCache(mpId, userId);
        if (wechatUser == null) {
            return JBoltApiRet.API_FAIL(application, "无法获取当前用户信息");
        }
        CACHE.me.removeApiWechatUserByMpOpenId(mpId, wechatUser.getOpenId());
        CACHE.me.removeApiWechatUser(mpId, wechatUser.getId());

        JBoltApiKit.removeApplyJwtUser();
        JBoltApiKit.removeApplyJwtUser();
        wechatUserService.deleteById(mpId, wechatUser.getId());
        return JBoltApiRet.API_SUCCESS;
    }

    public JBoltApiRet getMemberList(JBoltPara param) {
        Application application = JBoltApiKit.getApplication();
        Long mpId = JBoltApiKit.getWechatMpId();
        Integer pageNumber = param.getInteger("pageNumber");
        Integer pageSize = param.getInteger("pageSize");
        if (notOk(pageNumber)) {
            pageNumber = 1;
        }
        if (notOk(pageSize)) {
            pageSize = 1;
        }
        Page<Record> recordPage = wechatUserService.paginateAdminList(mpId, pageNumber, pageSize, null, null);
        JBoltCamelCaseUtil.keyToCamelCase(recordPage);
        return JBoltApiRet.successWithData(recordPage);
    }

    public JBoltApiRet getMemberInfo(Long id) {
        Application application = JBoltApiKit.getApplication();
        Long mpId = JBoltApiKit.getWechatMpId();
        if (notOk(id)) {
            return JBoltApiRet.API_FAIL(application, "id null");
        }
        WechatUser user = wechatUserService.findByIdToWechatUser(mpId, id);
        if (notOk(user)) {
            return JBoltApiRet.API_FAIL(application, "用户不存在");
        }
        return JBoltApiRet.successWithData(user);
    }
}
